/**
 * 
 */
package org.tuestudent.grouppa;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;

import org.apache.commons.lang3.StringEscapeUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.tuestudent.grouppa.AppContext.ActiveScreens;

/**
 * @author s121170 Class that services login views
 */
public class LoginViewController extends ViewController {

    /**
     * Hidden constructor, use getInstance()
     */
    private LoginViewController() {

    }

    static LoginViewController instance = null;

    static public LoginViewController getInstance() {
        if (instance != null)
            return instance;

        instance = new LoginViewController();
        return instance;
    }

    /**
     * logs in a user (providing the password is correct)
     * 
     * @param email
     *            email of the user to log in
     * @param password
     *            password of the user
     */
    public void login(String email, String password) {
        // CHECK: send request for user login
        MessageFromApp message = new MessageFromApp();
        message.from = "";
        message.messageType = "loginResponse";
        message.task = "login";
        message.toController = "GeneralServices";
        message.toGroup = "";
        message.serializedArguments =
                "{\"email\":\"" + email + "\",\"password\":\"" + password
                        + "\"}";
        Main.getConnection().sendMessage(message);
    }

    public class LoginResponse {

        public boolean succeeded;
        public String errorReason;
        public Group[] groups;
    }

    /**
     * Tries to create a new account
     * 
     * @param userName
     *            requested user name of a new account
     * @param password
     *            requested password of a new account
     * @param email
     *            email assigned for this new account
     */
    public void createAccount(String userName, String password, String email) {
        // CHECK: send request to create a new account
        MessageFromApp message = new MessageFromApp();
        message.from = userName;
        message.messageType = "createAccountResponse";
        message.task = "createAccount";
        message.toController = "GeneralServices";
        message.toGroup = "";
        message.serializedArguments =
                "{\"username\":\"" + userName + "\",\"password\":\"" + password
                        + "\"," + "\"email\":\"" + email + "\"}";
        Main.getConnection().sendMessage(message);
    }

    public class CreateAccountResponse {

        public boolean succeeded;
        public String errorReason;
    }

    /**
     * Tries to send a password for that user name, which is also the email
     * 
     * @param email
     *            email that was assigned to this username during account
     *            creation
     */
    public void resetPassword(String email) {
        // CHECK: send request to send an email with password for that user
        MessageFromApp message = new MessageFromApp();
        message.from = "";
        message.messageType = "resetPasswordResponse";
        message.task = "resetPassword";
        message.toController = "GeneralServices";
        message.toGroup = "";
        message.serializedArguments = "{\"email\":\"" + email + "\"}";
        Main.getConnection().sendMessage(message);
    }

    public class ResetPasswordResponse {

        public boolean succeeded;
        public String errorReason;
    }

    /**
     * gets User class with data belonging to current user
     * 
     */
    public void getProfile(String userName) {
        // TODO: take current user data from context
        MessageFromApp message = new MessageFromApp();
        message.from = userName;
        message.messageType = "getProfileResponse";
        message.task = "getProfile";
        message.toController = "UserAccount";
        message.toGroup = "";
        message.serializedArguments = "{\"userName\":\"" + userName + "\"}";
        Main.getConnection().sendMessage(message);
    }

    /**
     * changes profile of the user according to supplied data
     * 
     */
    public void changeProfile(User userdata) {
        // CHECK: take current user data from context
        MessageFromApp message = new MessageFromApp();
        message.from = Main.getContext().currentUserName;
        message.messageType = "changeProfileResponse";
        message.task = "changeProfile";
        message.toController = "UserAccount";
        message.toGroup = "";
        message.serializedArguments = "{\"userId\":" + userdata.id + "," +
                "\"email\":\"" + userdata.email + "\"," +
                "\"userName\":\"" + userdata.name + "\"," +
                "\"pin\":\"" + userdata.password + "\"," +
                "\"phone\":\"" + StringEscapeUtils.escapeJson(userdata.phone) + "\"," +
                "\"extraInfo\":\"" + StringEscapeUtils.escapeJson(userdata.extraInfo) + "\"}";
        Main.getConnection().sendMessage(message);
    }
    public class GetProfileResponse {

        public boolean succeeded;
        public String errorReason;
        public User userdata;
    }

    @Override
    public void onMessageReceived(MessageFromServer message) {
        AppContext ctx = Main.getContext();
        if (checkForError(message))
            return; // ignoring messages if login screen is not active
        if(ctx.activeScreen == ActiveScreens.login)
        {
            if (message.messageType.equals("loginResponse")) {
                processLoginResponse(message, ctx);
            } else if (message.messageType.equals("createAccountResponse")) {
    
                processCreateAccountResponse(message, ctx);
            } else if (message.messageType.equals("resetPasswordResponse")) {
    
                processResetPasswordResponse(message, ctx);
            }   
        } else 
        {
            if (message.messageType.equals("getProfileResponse")) {
                processGetProfileResponse(message, ctx);
            } else if (message.messageType.equals("changeProfileResponse")) {
                processChangeProfileResponse(message, ctx);
            }
        }
    }

    private void processResetPasswordResponse(MessageFromServer message,
            AppContext ctx) {
        ResetPasswordResponse response = new ResetPasswordResponse();
        try {
            JSONObject args = new JSONObject(message.serializedArguments);
            response.succeeded = args.optBoolean("emailSent");
            response.errorReason = args.optString("reason");
        } catch (Exception ex) {
            response.succeeded = false;
            response.errorReason = ex.getMessage();
        }
        ctx.loginActivity.onResetPasswordResponse(response);
    }

    private void processCreateAccountResponse(MessageFromServer message,
            AppContext ctx) {
        CreateAccountResponse response = new CreateAccountResponse();
        try {
            JSONObject args = new JSONObject(message.serializedArguments);
            response.succeeded = args.optBoolean("created");
            response.errorReason = args.optString("reason");
            if (response.succeeded) {
                ctx.currentAccessToken = args.getString("accessToken");
                ctx.currentUserName = args.getString("username");
            }
        } catch (Exception ex) {
            response.succeeded = false;
            response.errorReason = ex.getMessage();
        }
        ctx.loginActivity.onCreateAccountResponse(response);
    }
    private void processGetProfileResponse(MessageFromServer message,
            AppContext ctx) {
        UserProfile userProfile = UserProfile.getInstance();
        if(userProfile != null)
        {
            GetProfileResponse response = new GetProfileResponse();
            try {
                JSONObject args = new JSONObject(message.serializedArguments);
                response.succeeded = args.getBoolean("succeeded");
                response.errorReason = args.optString("reason");
                if (response.succeeded) {
                    User user = new User();
                    response.userdata = user;
                    user.password = args.optString("pin");
                    user.email = args.optString("email");
                    user.id = args.getInt("userId");
                    user.name = args.getString("username");
                    JSONObject extraInfo = args.optJSONObject("extra");
                    if(extraInfo != null)
                    {
                        user.phone = extraInfo.optString("phone");
                        if(user.phone != null)
                        {
                            user.phone = StringEscapeUtils.unescapeJson(user.phone);
                        }
                        user.extraInfo = extraInfo.optString("extraInfo");
                        if(user.extraInfo != null)
                        {
                            user.extraInfo = StringEscapeUtils.unescapeJson(user.extraInfo);
                        }
                    }
                }
            } catch (Exception ex) {
                response.succeeded = false;
                response.errorReason = ex.getMessage();
            }
            userProfile.onGetProfileResponse(response);
        }
    }
    private void processChangeProfileResponse(MessageFromServer message,
            AppContext ctx) {
        UserProfile userProfile = UserProfile.getInstance();
        if(userProfile != null)
        {
            GetProfileResponse response = new GetProfileResponse();
            try {
                JSONObject args = new JSONObject(message.serializedArguments);
                response.succeeded = args.getBoolean("succeeded");
                response.errorReason = args.optString("reason");
                if (response.succeeded) {
                    User user = new User();
                    response.userdata = user;
                    user.password = args.optString("pin");
                    user.email = args.optString("email");
                    user.id = args.getInt("userId");
                    user.name = args.getString("username");
                    JSONObject extraInfo = args.optJSONObject("extra");
                    if(extraInfo != null)
                    {
                        user.phone = args.optString("phone");
                        user.extraInfo = args.optString("extraInfo");
                    }
                }
            } catch (Exception ex) {
                response.succeeded = false;
                response.errorReason = ex.getMessage();
            }
            userProfile.onChangeProfileResponse(response);
        }
    }

    private void
            processLoginResponse(MessageFromServer message, AppContext ctx) {
        LoginResponse response = new LoginResponse();
        try {
            JSONObject args = new JSONObject(message.serializedArguments);
            response.succeeded = args.optBoolean("loggedIn");
            response.errorReason = args.optString("reason");
            if (response.succeeded) {
                ctx.currentAccessToken = args.getString("accessToken");
                ctx.currentUserName = args.getString("username");
                ctx.currentUserPassword = args.getString("pin");
                JSONArray groups = args.optJSONArray("groups");
                HashMap<String, Group> jgroups = Main.getContext().joinedGroups;
                jgroups.clear();
                if (groups != null) {
                    Group[] rGroups = new Group[groups.length()];
                    for (int i = 0; i < groups.length(); i++ ) {
                        JSONObject group = groups.getJSONObject(i);
                        rGroups[i] = new Group(group.getString("groupName"),group.getBoolean("isManager"),group.getString("pin"));
                        jgroups.put(rGroups[i].name, rGroups[i]);
                    }
                    response.groups = rGroups;
                } else
                    response.groups = new Group[0];
            }
        } catch (Exception ex) {
            response.succeeded = false;
            response.errorReason = ex.getMessage();
        }
        ctx.loginActivity.onLoginResponse(response);
    }

    @Override
    public void reset() {
        // TODO Auto-generated method stub
        
    }

}
